use crate::bcossdk::bcossdk::BcosSDK;
use crate::bcossdk::contractabi::ContractABI;
use crate::bcossdk::kisserror::KissError;
use crate::bcossdk::bcosclientconfig::{ClientConfig, BcosCryptoKind};
use crate::bcossdk::contracthistory::ContractHistory;
use crate::bcossdk::commonhash::CommonHash;
use ethabi::Log;
use crate::Cli;
use serde_json::{Value as JsonValue};

static  DELOPY_ADDRESS:&str = "0000000000000000000000000000000000000000";
pub fn is_deploy_address(address:&str)->bool{
    if address.trim_start_matches("0x").eq(DELOPY_ADDRESS){
        return true
    }else{
        return false;
    }
}

///从历史里根据地址查找合约实例
pub fn find_contracthistory_byaddress(contractpath:&str,crytokind:&BcosCryptoKind,address:&str)->Result<ContractABI,KissError>
{
       //从历史库中通过address获得contract对象
    let ch =ContractHistory::load_from_path(contractpath)?;
    let chrecord = ch.find_record_by_address(address)?;
    println!("find contract history by addess {:?}",chrecord);
    let contract = ContractABI::new_by_name(chrecord.name.as_str(),
                             contractpath,
                             &CommonHash::crypto_to_hashtype(crytokind))?;
    Ok(contract)
}


///根据名字或address去找一个合约实例
pub fn find_contract(nameopt:&Option<String>,address :&str,config:&ClientConfig)->Result<ContractABI,KissError>
{
        let contract = match &nameopt {
        Some(name)=>{
            let contract =  ContractABI::new_by_name(name,
                                              config.contract.contractpath.as_str(),
                                              &CommonHash::crypto_to_hashtype(&config.chain.crypto)
            ) ;
            println!("load contract by name : {}",name);
            return contract
        },
        Option::None=>{
                return find_contracthistory_byaddress(config.contract.contractpath.as_str(),
                                                         &config.chain.crypto,
                                                         address)

            }
    };
}


///显示回执里的logs
pub fn display_receipt_logs(logs:&Vec<Log>)
{
    let mut i = 0;
    for log in logs.iter(){
        i+=1;
        println!("{}) {:?})",i,log);
    }
}

///显示交易的回执
pub fn display_transaction_receipt(receipt:&JsonValue, contract:&ContractABI, config:&ClientConfig)
{
    println!("----------------------> Receipt summary-------------------->");
    //output ,status,contractaddress,logs
    let output = receipt["result"]["output"].as_str().unwrap();
    let status:&str =  receipt["result"]["status"].as_str().unwrap();
    let contractaddress =  receipt["result"]["contractAddress"].as_str().unwrap();
    let decordinput = contract.decode_input_for_tx(receipt["result"]["input"].as_str().unwrap()).unwrap();
    let outputres = decordinput.func.decode_output(output.as_bytes());
    let to = receipt["result"]["to"].as_str().unwrap();
    let outputdetail = match outputres{
        Ok(o)=>{o},
        Err(e)=>{vec!()} //置为空，供展示
    };
    //println!("receipt is {}",serde_json::to_string_pretty(receipt).unwrap());
   // println!("status {}",status);
    let istatus = i32::from_str_radix(status.trim_start_matches("0x"),16).unwrap();
    if is_deploy_address(contractaddress){
        println!("is Deploy Tx, result address :{} ",contractaddress);
    }else{
        println!("is Normal Tx, to address :{} ",to);
    }
    let msg = format!("status:{},func:[{}],output(decode):{:?}",istatus,decordinput.func.name,outputdetail);
    println!("{}",msg);
    let logs = contract.parse_receipt_logs(&receipt["result"]["logs"]).unwrap();
    display_receipt_logs(&logs);
}


/// 判断是否部署合约
/// 如果调用合约，在历史表里找合约记录
/// 找到的额话，解析交易的input
/// 获取交易对应的receipt，打印receipt
pub fn display_transaction(v:&JsonValue,bcossdk:&mut BcosSDK,cli:&Cli)->Result<(),KissError>
{
    println!("\n{}\n",serde_json::to_string_pretty(&v).unwrap());
    let to = v["result"]["to"].as_str().unwrap();
    println!("tx call to {}",to);
    if is_deploy_address(to) { //is deploy
        println!("a DEPLOY contract transaction");
        return Ok(())
    }

    let hash = v["result"]["hash"].as_str().unwrap();

    let contractres = find_contract(&cli.contractname,to,&bcossdk.config);
    let contract = match contractres {
                    Ok(c) => { c },
                    Err(e) => {
                        //miss ,but maybe not a error
                        println!("Missing contract history for address  [{}] ,but ok &done ", to);
                        return Ok(())
                    }
                };

    let receipt = bcossdk.getTransactionReceipt(hash)?;
    println!("----------------------> Transaction summary-------------------->");
    let decordres = contract.decode_input_for_tx(v["result"]["input"].as_str().unwrap())?;
    println!("tx input : {:?}, params :{:?}",decordres.func.signature(),decordres.input);
    Ok(())
}
